package com.google.code.hibernate.rest.method;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.code.hibernate.rest.internal.InternalStreams;

/**
 * 
 * @author wangzijian
 * 
 */
public final class Response {

	private static final Logger LOGGER = LoggerFactory.getLogger(Response.class);
	
	private final int code;
	private final String body;
	private final Map<String, String> headers;
	
	public static Response of(HttpURLConnection connection) throws IOException {
		return new Response(
				connection.getResponseCode(), 
				readBody(connection), 
				readHeaders(connection));
	}

	private static Map<String, String> readHeaders(HttpURLConnection connection) {
		Map<String, String> headers = new HashMap<String, String>();
		for (Entry<String, List<String>> each : connection.getHeaderFields().entrySet()) {
			headers.put(each.getKey(), onlyElementOf(each.getValue()));
		}
		return Collections.unmodifiableMap(headers);
	}

	private static <T> T onlyElementOf(List<T> list) {
		if (list != null && list.size() == 1) {
			return list.iterator().next();
		}
		throw new IllegalArgumentException("Cannot get only element from " + list);
	}

	private static String readBody(HttpURLConnection connection) {
		try {
			return InternalStreams.read(connection.getInputStream());
		} catch (IOException e) {
			try {
				return InternalStreams.read(connection.getErrorStream());
			} catch (IOException e1) {
				LOGGER.error("Read body error", e);
				return null;
			}
		}
	}
	
	public Response(int code, String body, Map<String, String> headers) {
		this.code = code;
		this.body = body;
		this.headers = headers;
	}

	public int getCode() {
		return code;
	}

	public String getBody() {
		return body;
	}

	public Map<String, String> getHeaders() {
		return headers;
	}
	
}
